package graph_viewer.structure;

import java.awt.*;

import graph_viewer.layout.*;
import graph_viewer.util.*;

/**
 * Define the node position
 */
public class Node_Position{	
	private int	x_center, y_center;
	private int	height, width;
	
	private	boolean			is_fixed;		// if a node is fixed, it dose not move when involved in spring alg.
	//============================================================================
	// construtors
	//============================================================================
	public Node_Position(){		
		// using this(int[])
		this( Node_Position_Helper.poistion_randomizer() );		
    }
	
	public Node_Position( Node_Position np ){
		this( np.get_x_center(), np.get_y_center(), np.get_width(), np.get_height() );
	}

	public Node_Position( Fisheye_Point center, int w, int h ){
		this( center.getX(), center.getY(), w, h );
	}

	public Node_Position( Fisheye_Point center, double w, double h ){
		this( center.getX(), center.getY(), (int)w, (int)h );
	}
	
	public Node_Position( int x_center, int y_center,int width , int height ){
		set_x_center( x_center );
		set_y_center( y_center );
		set_width( width );
		set_height( height );

		set_is_fixed( false );
	}
	
	public Node_Position ( Point point, int width, int height ){
		this( (int)point.getX(), (int)point.getY(), width, height );
	}
	
	public Node_Position( int[] xy, int width, int height ){
		this( xy[0], xy[1], width, height );
	}
	public Node_Position( int[] xy ){
		this( xy[0], xy[1] );
	}

	public Node_Position( int x_center, int y_center ){
		this( x_center, y_center, Layout.DEFAULT_NODE_WIDTH, Layout.DEFAULT_NODE_HEIGHT );
    }
		
	public Node_Position( Fisheye_Point p ){
		this( p.getX(), p.getY() );
	}
	
	//============================================================================
	// public methods 
	//============================================================================
	public int[] find_location(){
		int x_location, y_location;
		x_location = x_center - width/2;
		y_location = y_center - height/2;

		return new int[]{ x_location, y_location };
	}

	public int[] find_center(){
		return new int[]{ x_center, y_center };
	}
	
	public Point find_center_point(){
		return new Point( x_center, y_center );
	}

	public Point find_location_piont(){
		int[] location = find_location();

		return new Point( location[0], location[1] );
	}
		
	public int[] find_right_bottom(){
		int x_location, y_location;
		x_location = x_center + width/2;
		y_location = y_center + height/2;

		return new int[]{ x_location, y_location };
	}
	

	//@return four corner points at clockwise direction
	public Point[] find_corners(){
		int[] 
			left_top			= find_location(),
			right_bottom	= find_right_bottom();

		Point
			left_top_corner		= new Point( left_top[0], left_top[1] ),
			right_top_corner		= new Point( right_bottom[0], left_top[1] ),
			right_bottom_corner	= new Point( right_bottom[0], right_bottom[1] ),
			left_bottom_corner	= new Point( left_top[0], right_bottom[1] );
		
		return new Point[]{left_top_corner, right_top_corner, right_bottom_corner, left_bottom_corner };

	}
	
	public Rectangle find_position_range(){
		int[] location = find_location();
		
		return new Rectangle( location[0], location[1], width + 1, height + 1 );
	}

	//@return the max(height, width )
	public int find_radis(){
		return Math.max(get_width(), get_height());
	}
	
	//setposition by @corners point
	public void 	reallocate_by_corner_points( Point[] corners ){
		Point
			left_top_corner		= corners[0],
			right_top_corner		= corners[1],
			right_bottom_corner	= corners[2],
			left_bottom_corner	= corners[3];

		double 
			width		= right_top_corner.getX() - left_top_corner.getX(),
			height	= left_bottom_corner.getY() - left_top_corner.getY();

		int
			x_center	 = (int)( right_top_corner.getX()  + width/2 ),
			y_center	 = (int)( left_top_corner.getY() + height/2 );

		set_x_center( x_center );
		set_y_center( y_center );
		set_width( (int)width );
		set_height( (int)height );
	}

	public void relocate( int new_location[] ){
		int[] current_location	= find_location();

		int
			x_adjust	 = current_location[0] - new_location[0],
			y_adjust	 = current_location[1] - new_location[1];

		int
			new_x_center	= x_center - x_adjust,
			new_y_center	= y_center - y_adjust;
		
		set_x_center( new_x_center );
		set_y_center( new_y_center );
	}
	
	public int find_diameter_length(){
		double 
			node_1_width	= get_width(),
			node_1_height	= get_height();

		int diameter_length = (int)Math.sqrt( node_1_width * node_1_width + node_1_height * node_1_height );

		return diameter_length;
	}



	public boolean contains( int x, int y ){
		boolean x_inside, y_inside;

		x_inside	= ( x >= ( this.x_center - width/2 ) ) && ( x <= ( this.x_center + width/2 ) );
		y_inside	= ( y >= ( this.y_center - height/2 ) ) && ( y <= ( this.y_center + height/2 ) );  

		return x_inside && y_inside;
	}
	
	public int[] get_top_point(){
		int	
			x	= get_x_center(),
			y	= get_y_center() - get_height()/2;

		return new int[]{ x, y };
	}

	public int[] get_bottom_point(){
		int	
			x	= get_x_center(),
			y	= get_y_center() + get_height()/2;

		return new int[]{ x, y };
	}

	public int[] get_left_point(){
		int		
			x	= get_x_center() - get_width()/2,
			y	= get_y_center();

		return new int[] { x, y };
	}

	public int[] get_right_point(){
		int	
			x	= get_x_center() + get_width()/2,
			y	= get_y_center();
		
		return new int[] { x, y };
	}

	public boolean is_left( Node_Position another_node ){
		int 
			this_center	= this.get_x_center(),
			another_center	= another_node.get_x_center();

		return this_center < another_center;
	}
	
	public boolean is_right( Node_Position another_node ){
		int 
			this_center	= this.get_x_center(),
			another_center	= another_node.get_x_center();

		return this_center > another_center;
	}

	public boolean is_above( Node_Position another_node ){
		int 
			this_center	= this.get_y_center(),
			another_center	= another_node.get_y_center();

		return this_center < another_center;		
	}

	public boolean is_below( Node_Position another_node ){
		int 
			this_center	= this.get_y_center(),
			another_center	= another_node.get_y_center();

		return this_center > another_center;		
	}

	public boolean is_overlapped( Node_Position another_node_position ){
		boolean
			is_x_overlapped	= is_x_overlapped( another_node_position ),
			is_y_overlapped	= is_y_overlapped( another_node_position );

		return is_x_overlapped && is_y_overlapped;		
	}
	
		
	public boolean is_on_horizontal_line( Node_Position neighbour_node_position){
		int 
			current_node_y_center		= get_y_center(),
			neighbour_node_y_center	= neighbour_node_position.get_y_center();

		return current_node_y_center == neighbour_node_y_center;
	}

	public boolean is_on_vertical_line( Node_Position neighbour_node_position){
		int 
			current_node_x_center		= get_x_center(),
			neighbour_node_x_center	= neighbour_node_position.get_x_center();

		return current_node_x_center == neighbour_node_x_center;
	}

	public double find_aspect_ratio(){
		double 	aspect_ratio;
		
		
		if ( width < height ){
			aspect_ratio = (double )height/(double )width;
		}else{
			aspect_ratio = (double )width/(double )height;
		}

		return aspect_ratio;
	}
	
	public String toString(){
		StringBuffer position = new StringBuffer();
		position.append( "\t{" + get_x_center() );
		position.append( ", " + get_y_center() );
		
		//position.append( "\t{x_location is:" + find_location()[0] );
		//position.append( ",  y_location is:" + find_location()[1] + "}" );
		//position.append( ", location is:" + find_location() [0] + ", " +  find_location() [0] );

		position.append( ", " + get_width() );
		position.append( ", " + get_height() );
		position.append( "}" );
		
		return position.toString();
	}



	//============================================================================
	// setter & getter
	//============================================================================
	public void set_center( int[] center ){
		set_x_center( center[0]);
		set_y_center( center[1]);	
	}
	
	public void set_center( Point center_point ){
		set_x_center( (int)center_point.getX() );
		set_y_center( (int)center_point.getY() );
	}
	
	public void set_x_center( int x_center ){
		this.x_center	= x_center;
	}

	public int get_x_center(){
		return this.x_center;
	}

	public void set_y_center( int y_center ){
		this.y_center	= y_center;
	}
	
	public int get_y_center(){
		return this.y_center;
	}

	public void set_height( int height ){
		this.height	= height;
	}

	public void set_width ( int width ){
		this.width = width;
	}

	public int get_width(){
		return this.width;
	}

	public int get_height(){
		return this.height;
	}
	
	public void set_is_fixed( boolean status ){
		this.is_fixed	= status;
	}

	public boolean get_is_fixed(){
		return this.is_fixed;
	}
	//============================================================================
	// private
	//============================================================================
	private boolean is_x_overlapped( Node_Position another_node_position ){
		int[]
			this_left_point			= get_left_point(),
			this_right_point		= get_right_point(),

			another_left_point	= another_node_position.get_left_point(),
			another_right_point	= another_node_position.get_right_point();
		// to avoid minus value
		int 
			this_x_left			= this_left_point[0], // - Layout.NODE_MARGIN,
			this_x_right			= this_right_point[0], // + Layout.NODE_MARGIN,
			another_x_lef		= another_left_point[0],
			another_x_right	= another_right_point[0];
		
		
		boolean
			overlap_case_1	= ( this_x_left <= another_x_lef ) && ( this_x_right >= another_x_lef ),//this left to another;
			overlap_case_2	= ( this_x_left >= another_x_lef ) && ( this_x_left <= another_x_right );//this right than another;

		return overlap_case_1 || overlap_case_2;
				
	}
	
	private boolean is_y_overlapped( Node_Position another_node_position ){
		int[] 
			this_top_point			= get_top_point(),
			this_bottom_point	= get_bottom_point(),
			
			another_top_point		= another_node_position.get_top_point(),
			another_bottom_point	= another_node_position.get_bottom_point();

		int
			this_y_top		= this_top_point[1], // - Layout.NODE_MARGIN + 1,
			this_y_bottom		= this_bottom_point[1], // + Layout.NODE_MARGIN -1 ,
			another_y_top		= another_top_point[1],
			another_y_bottom	= another_bottom_point[1];

		boolean
			overlap_case_1	= ( this_y_top <= another_y_top ) && ( this_y_bottom >= another_y_top ),//this higher than another;
			overlap_case_2	= ( this_y_top >= another_y_top ) && ( this_y_top <= another_y_bottom );//this lower than another;

		return overlap_case_1 || overlap_case_2;
	}
}
